// phalanx move.hpp.cu header file

// Copyright (c) 2010 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

// Redefinition Boost.Move

#ifndef IG_PHALANX_MOVE_MOVE_HPP_CU_ONCE_
#define IG_PHALANX_MOVE_MOVE_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <boost/static_assert.hpp>

#include <boost/preprocessor/cat.hpp>

#include <boost/mpl/not.hpp>
#include <boost/mpl/and.hpp>

#include <phalanx/move/detail/rvalue.hpp.cu>
#include <phalanx/move/detail/is_move_reference.hpp.cu>
#include <phalanx/move/detail/is_movable.hpp.cu>
#include <phalanx/move/detail/remove_move_reference.hpp.cu>

#include <phalanx/utility/identity.hpp.cu>
#include <phalanx/utility/enable_if.hpp.cu>

#include <phalanx/type_traits/is_lvalue_reference.hpp.cu>
#include <phalanx/type_traits/remove_reference.hpp.cu>

namespace phalanx
{

#define PHALANX_MOVABLE( T_ ) \
  private: \
      typedef ::phalanx::move_detail::rv_< T_ > \
        BOOST_PP_CAT( phalanx_unnamed_rv_, __LINE__ ); \
      typedef       BOOST_PP_CAT( phalanx_unnamed_rv_, __LINE__ ) * \
        BOOST_PP_CAT( phalanx_unnamed_rv_pointer_, __LINE__ ); \
      typedef const BOOST_PP_CAT( phalanx_unnamed_rv_, __LINE__ ) * \
        BOOST_PP_CAT( phalanx_unnamed_rv_cpointer_, __LINE__ ); \
      typedef       BOOST_PP_CAT( phalanx_unnamed_rv_, __LINE__ ) & \
        BOOST_PP_CAT( phalanx_unnamed_rv_ref_, __LINE__ ); \
      typedef const BOOST_PP_CAT( phalanx_unnamed_rv_, __LINE__ ) & \
        BOOST_PP_CAT( phalanx_unnamed_rv_cref_, __LINE__ ); \
  public: \
      PHALANX_CONFIG_DEFAULT_FUNCTION( true ) \
      operator BOOST_PP_CAT( phalanx_unnamed_rv_ref_, __LINE__ )( void ) \
      { \
          typedef BOOST_PP_CAT( phalanx_unnamed_rv_pointer_, __LINE__ ) \
            local_pointer; \
          return *reinterpret_cast< local_pointer >( this ); \
      } \
      PHALANX_CONFIG_DEFAULT_FUNCTION( true ) \
      operator BOOST_PP_CAT( phalanx_unnamed_rv_cref_, __LINE__ )( void ) const \
      { \
          typedef BOOST_PP_CAT( phalanx_unnamed_rv_cpointer_, __LINE__ ) \
            local_cpointer; \
          return *reinterpret_cast< local_cpointer >( this ); \
      } \
  private: \
      struct BOOST_PP_CAT( T_, _is_already_movable ) {} \

// perfect forwarding
template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename enable_if<
  move_detail::is_move_reference< T >,
  T >::type
forward( typename identity< T >::type x )
{ return x; }

template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename enable_if<
  ::boost::mpl::and_<
    ::boost::mpl::not_< move_detail::is_move_reference< T > >,
    ::boost::mpl::not_< is_lvalue_reference< T > > >,
  const T & >::type
forward( const typename identity< T >::type &x )
{ return x; }

// instanced by lvalue reference
template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename enable_if<
  ::boost::mpl::and_<
    ::boost::mpl::not_< move_detail::is_move_reference< T > >,
    is_lvalue_reference< T > >,
  const T & >::type
forward( typename identity< T >::type x )
{
    BOOST_STATIC_ASSERT( !is_lvalue_reference< T >::value );
    return x;
}

// moving
// note: C++03 cannot check that object is temporary or not-temporary.
//  Threfore, programmers are forced to use phalanx::forward()
//  for moving the temporary object.
template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename disable_if<
  move_detail::is_movable< T >,
  T & >::type
move( T &x )
{ return x; }

template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename enable_if<
  move_detail::is_movable< T >,
  PHALANX_RV_REF( T ) >::type
move( T &x )
{ return static_cast< PHALANX_RV_REF( T ) >( x ); }

template < typename T >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename enable_if<
  move_detail::is_movable< T >,
  PHALANX_RV_REF( T ) >::type
move( PHALANX_RV_REF( T ) x )
{ return x; }

} // namespace phalanx

#endif // IG_PHALANX_MOVE_MOVE_HPP_CU_ONCE_

